/***************************************************************************
 * Copyright 2012-2013 TXT e-solutions SpA
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * This work was performed within the IoT_at_Work Project
 * and partially funded by the European Commission's
 * 7th Framework Programme under the contract ICT-257367.
 *
 * Authors:
 *      Salvatore Piccione (TXT e-solutions SpA)
 *
 * Contributors:
 *        Domenico Rotondi (TXT e-solutions SpA)
 **************************************************************************/
package it.txt.ens.core.impl;

import it.txt.ens.core.ENSAuthzServiceConnectionParameters;
import it.txt.ens.core.factory.ENSAuthzServiceConnectionParametersFactory;
import it.txt.ens.core.util.validator.BrokerPortValidator;

/**
 * This class provides the default implmentation of the interface {@link ENSAuthzServiceConnectionParameters}.
 * 
 * @author Salvatore Piccione (TXT e-solutions SpA - salvatore.piccione AT txtgroup.com)
 * @author Domenico Rotondi (TXT e-solutions SpA - domenico.rotondi AT txtgroup.com)
 *
 */
public class BasicENSAuthzServiceConnectionParameters implements ENSAuthzServiceConnectionParameters {
    
    private final String subjectID;
    private final String accessToken;
    private final String brokerHost;
    private final int brokerPort;
    private final String destinationName;
    private final String virtualHost;
    private final boolean tlsEnabled;
    private final int mgmtPort;
    
    private BasicENSAuthzServiceConnectionParameters (Builder builder) {
        subjectID = builder.subjectID;
        accessToken = builder.accessToken;
        brokerHost = builder.brokerHost;
        brokerPort = builder.brokerPort;
        destinationName = builder.destinationName;
        virtualHost = builder.virtualHost;
        tlsEnabled = builder.tlsEnabled;
        mgmtPort = builder.mgmtPort;
    }

    /* (non-Javadoc)
     * @see it.txt.ens.core.ENSConnectionParameters#getSubjectID()
     */
    public String getSubjectID() {
        return subjectID;
    }

    /* (non-Javadoc)
     * @see it.txt.ens.core.ENSConnectionParameters#getAccessToken()
     */
    public String getAccessToken() {
        return accessToken;
    }

    /* (non-Javadoc)
     * @see it.txt.ens.core.ENSConnectionParameters#getBrokerHost()
     */
    public String getBrokerHost() {
        return brokerHost;
    }

    /* (non-Javadoc)
     * @see it.txt.ens.core.ENSConnectionParameters#getBrokerPort()
     */
    public int getBrokerPort() {
        return brokerPort;
    }

    /* (non-Javadoc)
     * @see it.txt.ens.core.ENSConnectionParameters#getVirtualHost()
     */
    public String getVirtualHost() {
        return virtualHost;
    }

    /* (non-Javadoc)
     * @see it.txt.ens.core.ENSConnectionParameters#getDestinationName()
     */
    public String getDestinationName() {
        return destinationName;
    }
    
    /* (non-Javadoc)
     * @see it.txt.ens.core.ENSConnectionParameters#isTLSEnabled()
     */
    public boolean isTLSEnabled() {
        return tlsEnabled;
    }
    
    /**
     * Creates {@link BasicENSAuthzServiceConnectionParameters} objects using the <i>Builder</i> pattern.
     * @author Salvatore Piccione (TXT e-solutions SpA - salvatore.piccione AT txtgroup.com)
     * @author Domenico Rotondi (TXT e-solutions SpA - domenico.rotondi AT txtgroup.com)
     *
     */
    public static class Builder {
        private final String subjectID;
        private final String accessToken;
        private final String destinationName;
        private String brokerHost = ENSAuthzServiceConnectionParametersFactory.DEFAULT_BROKER_HOST;
        private int brokerPort = ENSAuthzServiceConnectionParametersFactory.DEFAULT_BROKER_PORT;
        private String virtualHost = ENSAuthzServiceConnectionParametersFactory.DEFAULT_VIRTUAL_HOST;
        private boolean tlsEnabled = ENSAuthzServiceConnectionParametersFactory.DEFAULT_TLS_FLAG;
        private int mgmtPort = ENSAuthzServiceConnectionParametersFactory.DEFAULT_MGMT_PORT;
        
        /**
         *  Creates a new Builder whose mandatory fields are set with the given parameters.
         * @param subjectID the identifier of the Access Request Broker user.
         * @param accessToken the access token to be used when connecting to the Access Request Broker.
         * @param destinationName the name of the virtual host resource
         * to be used to receive or submit access requests (i.e. either an AMQP queue or exchange).
         * @throws IllegalArgumentException if at least one parameter is <code>null</code>
         * or an empty string
         */
        public Builder (String subjectID, String accessToken, String destinationName)
        throws IllegalArgumentException {
            if (subjectID == null)
                throw new IllegalArgumentException("The subjectID cannot be null");
            if (subjectID.length() == 0)
                throw new IllegalArgumentException("The subjectID cannot be an empty string");
            if (accessToken == null)
                throw new IllegalArgumentException("The access token cannot be null");
            if (accessToken.length() == 0)
                throw new IllegalArgumentException("The access token cannot be an empty string");
            if (destinationName == null)
                throw new IllegalArgumentException("The destination name cannot be null");
            if (destinationName.length() == 0)
                throw new IllegalArgumentException("The destination name cannot be an empty string");
            this.subjectID = subjectID;
            this.accessToken = accessToken;
            this.destinationName = destinationName;
        }
        
        /**
         * Sets the host name/IP address of the Access Request Broker
         * @param brokerHost the host name/IP address of the Access Request Broker
         * @return a reference to this object
         * @throws IllegalArgumentException if <code>brokerHost</code> is <code>null</code>
         * or an empty string
         */
        public Builder brokerHost (String brokerHost) throws IllegalArgumentException {
            if (brokerHost == null)
                throw new IllegalArgumentException("The broker host cannot be null");
            if (brokerHost.length() == 0)
                throw new IllegalArgumentException("The broker host cannot be an empty string");
            this.brokerHost = brokerHost;
            return this;
        }
        
        /**
         * Sets the TCP listening port of the Access Request Broker.
         * 
         * @param brokerPort the TCP listening port of the Access Request Broker
         * @return a reference to this object
         * @throws IllegalArgumentException if <code>brokerPort</code> is not in the range
         * [{@value it.txt.ens.core.util.validator.BrokerPortValidator#MIN_PORT_NUMBER}, 
         * {@value it.txt.ens.core.util.validator.BrokerPortValidator#MAX_PORT_NUMBER}]
         * 
         */
        public Builder brokerPort (int brokerPort) throws IllegalArgumentException {
            if (!BrokerPortValidator.isValid(brokerPort))
                throw new IllegalArgumentException("The broker host cannot be null");
            this.brokerPort = brokerPort;
            return this;
        }
        
        /**
         * Sets the HTTP listening port of the Access Request Broker.
         * @param mgmtPort the HTTP listening port of the Access Request Broker.
         * @return a reference to this object
         * @throws IllegalArgumentException if <code>mgmtPort</code> is not in the range
         * [{@value it.txt.ens.core.util.validator.BrokerPortValidator#MIN_PORT_NUMBER}, 
         * {@value it.txt.ens.core.util.validator.BrokerPortValidator#MAX_PORT_NUMBER}]
         */
        public Builder mgmtPort (int mgmtPort) throws IllegalArgumentException {
            if (!BrokerPortValidator.isValid(mgmtPort))
                throw new IllegalArgumentException("The broker host cannot be null");
            this.mgmtPort = mgmtPort;
            return this;
        }
        
        /**
         * Sets the flag indicating whether the TLS connection is enabled
         * 
         * @param isEnabled <code>true</code> if the communication should flow through a TLS-secured channel,
         * <code>false</code> otherwise
         * @return a reference to this object
         */
        public Builder tlsEnabled (boolean isEnabled) {
            this.tlsEnabled = isEnabled;
            return this;
        }
        
        /**
         * Sets the name of the virtual host
         * 
         * @param virtualHost the name of the AMQP virtual host
         * @return a reference to this object
         * @throws IllegalArgumentException if <code>virtualHost</code> is <code>null</code> or an
         * empty string
         */
        public Builder virtualHost (String virtualHost) throws IllegalArgumentException {
            if (virtualHost == null)
                throw new IllegalArgumentException("The virtual host cannot be null");
            if (virtualHost.length() == 0)
                throw new IllegalArgumentException("The virtual host cannot be an empty string");
            this.virtualHost = virtualHost;
            return this;
        }
        /**
         * Returns a new <code>BasicENSAuthzServiceConnectionParameters</code> object
         * @return a new <code>BasicENSAuthzServiceConnectionParameters</code> object
         */
        public BasicENSAuthzServiceConnectionParameters build () {
            return new BasicENSAuthzServiceConnectionParameters(this);
        }
    }
    
    /**
     * Provides the default implementation of {@link ENSAuthzServiceConnectionParametersFactory}<br/>It creates
     * {@link ENSAuthzServiceConnectionParameters} objects.
     * 
     * @author Salvatore Piccione (TXT e-solutions SpA - salvatore.piccione AT txtgroup.com)
     * @author Domenico Rotondi (TXT e-solutions SpA - domenico.rotondi AT txtgroup.com)
     *
     */
    public static class BasicENSConnectionParametersFactory implements ENSAuthzServiceConnectionParametersFactory {
        
        @Override
        public ENSAuthzServiceConnectionParameters create(String subjectID,
                String accessToken, String destinationName)
                throws IllegalArgumentException {
            Builder builder = new Builder(subjectID, accessToken, destinationName);
            return builder.build();
        }

        @Override
        public ENSAuthzServiceConnectionParameters create(String subjectID,
                String accessToken, String brokerHost, int brokerPort,
                String virtualHost, String destinationName, boolean tlsEnabled)
                throws IllegalArgumentException {
            Builder builder = new Builder(subjectID, accessToken, destinationName);
            if (null != brokerHost)
                builder.brokerHost(brokerHost);
            builder.brokerPort(brokerPort);
            if (null != virtualHost)
                builder.virtualHost(virtualHost);
            builder.tlsEnabled(tlsEnabled);
            return builder.build();
        }

        /* (non-Javadoc)
         * @see it.txt.ens.core.factory.ENSAuthzServiceConnectionParametersFactory#create(java.lang.String, java.lang.String, java.lang.String, int, int, java.lang.String, java.lang.String, boolean)
         */
        @Override
        public ENSAuthzServiceConnectionParameters create(String subjectID,
                String accessToken, String brokerHost, int brokerPort,
                int mgmtPort, String virtualHost, String destinationName,
                boolean tlsEnabled) throws IllegalArgumentException {
            Builder builder = new Builder(subjectID, accessToken, destinationName);
            if (null != brokerHost)
                builder.brokerHost(brokerHost);
            builder.brokerPort(brokerPort);
            builder.mgmtPort(mgmtPort);
            if (null != virtualHost)
                builder.virtualHost(virtualHost);
            builder.tlsEnabled(tlsEnabled);
            return builder.build();
        }
    }

    /* (non-Javadoc)
     * @see it.txt.ens.core.ENSAuthzServiceConnectionParameters#getHTTPPort()
     */
    @Override
    public int getManagementPort() {
        return this.mgmtPort;
    }
}
